﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Data;
using System.Configuration;
using System.Data.SqlClient;
using System.Xml.Serialization;
using ABC.Core.Configuration;
using ABC.Domain.Serialization;

namespace ABC.Business.Models
{
    /// <summary>
    /// Summary description for CalcOSAGO
    /// </summary>
    public class CalcOsagoModel : IDisposable
    {
        /**/
        public bool IsФизЛицо;
        public КатегорияТС катагорияТС;
        public string Регион;
        public bool IsБезОграничений;
        public double МинВозраст;
        public double МинСтаж;
        public double Мощность;
        public int ПериодСтрахования;
        public int МинКБМ;
        public double ПремияПоПолису;
        private readonly RosModel rosModel;

        /* Базовая ставка страхового тарифа */

        public double Тб
        {
            get
            {
                var k = 0;

                if (катагорияТС == КатегорияТС.А)
                    k = 1215;
                else if (IsФизЛицо && катагорияТС == КатегорияТС.B)
                    k = 1980;
                else if (!IsФизЛицо && катагорияТС == КатегорияТС.B)
                    k = 2375;
                else if (катагорияТС == КатегорияТС.C)
                    k = 2025;
                else if (катагорияТС == КатегорияТС.C2)
                    k = 3240;
                else if (катагорияТС == КатегорияТС.D)
                    k = 1620;
                else if (катагорияТС == КатегорияТС.D2)
                    k = 2025;
                else if (катагорияТС == КатегорияТС.Тракторы)
                    k = 1215;
                else if (катагорияТС == КатегорияТС.Прицепы)
                    k = 395;
                else if (катагорияТС == КатегорияТС.Прицепы2)
                    k = 810;
                else if (катагорияТС == КатегорияТС.Прицепы3)
                    k = 305;

                return k;
            }
        }

        /* Коэффициент в зависимости от территории использования ТС */

        public double Кт { get; set; }

        /* Коэффициент в зависимости от кол-ва допущенных к управлению ТС */

        public double Ко
        {
            get
            {
                /* Значения по умолчанию для Юр. лиц */
                if (!IsФизЛицо && катагорияТС == КатегорияТС.B)
                    return 1.7;
                else if (!IsФизЛицо)
                    return 1.7;

                return IsБезОграничений ? dicКо["Неограничено"] : dicКо["Ограничено"];
            }
        }

        /* Коэффициент в зависимости от стажа и возраста, допущенных у управлению ТС */

        public double Квс
        {
            get
            {
                if (IsБезОграничений) return 1;

                var item = dicКвс.SingleOrDefault(p =>
                                                  МинВозраст > p.AgeFrom && МинВозраст <= p.AgerTo &&
                                                  МинСтаж > p.СтажFrom && МинСтаж <= p.СтажTo);

                return item == null ? 0 : item.Value;
            }
        }

        /* Коэффициент в зависимости от мощности двигателя ТС */

        public double Км
        {
            get
            {
                var item = dicКм.SingleOrDefault(p => Мощность > p.PowerFrom && Мощность <= p.PowerTo);
                return item == null ? 0 : item.Value;
            }
        }

        /* Коэффициент в зависимости от периода использования ТС */

        public double Кс
        {
            get
            {
                /* Значения по умолчанию для Юр. лиц */
                if (!IsФизЛицо && катагорияТС == КатегорияТС.B)
                    return 1.0;

                return dicКс.ContainsKey(ПериодСтрахования) ? dicКс[ПериодСтрахования] : 0;
            }
        }

        /* Коэффициент в зависимости от наличия или отсутствия страховых выплат */

        public double Кбм
        {
            get { return dicКбм.ContainsKey(МинКБМ.ToString()) ? dicКбм[МинКБМ.ToString()] : 0; }
        }

        /* Коэффициент возвращает по умолчанию 1 */

        public double Кп
        {
            get { return 1; }
        }

        /* Словари */

        /* Коэффициент в зависимости от кол-ва допущенных к управлению ТС */
        public Dictionary<string, double> dicКо;

        /* Коэффициент в зависимости от стажа и возраста, допущенных у управлению ТС */
        public List<ОСАГО_Квс> dicКвс;

        /* Коэффициент в зависимости от периода использования ТС */
        public List<ОСАГО_Км> dicКм;

        /* Коэффициент в зависимости от периода использования ТС */
        public Dictionary<int, double> dicКс;

        /* Коэффициент в зависимости от наличия отсутствия страховых выплат */
        public Dictionary<string, double> dicКбм;

        public CalcOsagoModel()
        {
            rosModel = IoC.Resolve<RosModel>();

            /* инициируем словарь Ко */
            dicКо = new Dictionary<string, double>();
            dicКо.Add("Ограничено", 1);
            dicКо.Add("Неограничено", 1.7);

            /* инициируем словарь Квс */
            dicКвс = new List<ОСАГО_Квс>();
            dicКвс.Add(new ОСАГО_Квс()
                           {
                               Name = "Возраст до 22 лет включительно, стаж до 3 лет  включительно",
                               Value = 1.7,
                               AgeFrom = 0,
                               AgerTo = 22,
                               СтажFrom = -1,
                               СтажTo = 3
                           });
            dicКвс.Add(new ОСАГО_Квс()
                           {
                               Name = "Возраст до 22 лет включительно, стаж свыше 3 лет",
                               Value = 1.3,
                               AgeFrom = 0,
                               AgerTo = 22,
                               СтажFrom = 3,
                               СтажTo = 99
                           });
            dicКвс.Add(new ОСАГО_Квс()
                           {
                               Name = "Возраст более 22 лет, стаж до 3 лет включительно",
                               Value = 1.5,
                               AgeFrom = 22,
                               AgerTo = 99,
                               СтажFrom = -1,
                               СтажTo = 3
                           });
            dicКвс.Add(new ОСАГО_Квс()
                           {
                               Name = "Возраст более 22 лет, стаж свыше 3 лет",
                               Value = 1.0,
                               AgeFrom = 22,
                               AgerTo = 99,
                               СтажFrom = 3,
                               СтажTo = 99
                           });

            /* инициируем словарь Км */
            dicКм = new List<ОСАГО_Км>();
            dicКм.Add(new ОСАГО_Км() { Name = "до 50 включительно", Value = 0.6, PowerFrom = 0, PowerTo = 50 });
            dicКм.Add(new ОСАГО_Км() { Name = "свыше 50 до 70 включительно", Value = 0.9, PowerFrom = 50, PowerTo = 70 });
            dicКм.Add(new ОСАГО_Км() { Name = "свыше 70 до 100 включительно", Value = 1.0, PowerFrom = 70, PowerTo = 100 });
            dicКм.Add(new ОСАГО_Км() { Name = "свыше 100 до 120 включительно", Value = 1.2, PowerFrom = 100, PowerTo = 120 });
            dicКм.Add(new ОСАГО_Км() { Name = "свыше 120 до 150 включительно", Value = 1.4, PowerFrom = 120, PowerTo = 150 });
            dicКм.Add(new ОСАГО_Км() { Name = "свыше 150", Value = 1.6, PowerFrom = 150, PowerTo = 1001 });

            /* инициируем словарь Кс */
            dicКс = new Dictionary<int, double>();
            dicКс.Add(-3, 0.2);
            dicКс.Add(-2, 0.2);
            dicКс.Add(-1, 0.3);
            dicКс.Add(1, 0.4);
            dicКс.Add(2, 0.4);
            dicКс.Add(3, 0.4);
            dicКс.Add(4, 0.5);
            dicКс.Add(5, 0.6);
            dicКс.Add(6, 0.7);
            dicКс.Add(7, 0.8);
            dicКс.Add(8, 0.9);
            dicКс.Add(9, 0.95);
            dicКс.Add(10, 1);
            dicКс.Add(11, 1);
            dicКс.Add(12, 1);

            /* инициируем словарь Кбм */
            dicКбм = new Dictionary<string, double>();
            dicКбм.Add("-1", 2.45);
            dicКбм.Add("0", 2.3);
            dicКбм.Add("1", 1.55);
            dicКбм.Add("2", 1.4);
            dicКбм.Add("3", 1.0);
            dicКбм.Add("4", 0.95);
            dicКбм.Add("5", 0.9);
            dicКбм.Add("6", 0.85);
            dicКбм.Add("7", 0.8);
            dicКбм.Add("8", 0.75);
            dicКбм.Add("9", 0.7);
            dicКбм.Add("10", 0.65);
            dicКбм.Add("11", 0.6);
            dicКбм.Add("12", 0.55);
            dicКбм.Add("13", 0.5);
        }

        public double CalcСтраховаяПремия(bool IsФизЛицо, КатегорияТС катагорияТС, string Регион,
                                          bool IsБезОграничений, double МинВозраст, double МинСтаж, double Мощность,
                                          int ПериодСтрахования, int МинКБМ)
        {
            this.IsФизЛицо = IsФизЛицо;
            this.катагорияТС = катагорияТС;
            this.Регион = Регион;
            this.IsБезОграничений = IsБезОграничений;
            this.МинВозраст = МинВозраст;
            this.МинСтаж = МинСтаж;
            this.Мощность = Мощность;
            this.ПериодСтрахования = ПериодСтрахования;
            this.МинКБМ = МинКБМ;

            ПремияПоПолису = 0;
            Кт = Double.Parse(rosModel.GetEntityValue<string>(Регион, "ИдентификаторОбъекта"), CultureInfo.InvariantCulture);

            /* Расчет */
            if (катагорияТС == КатегорияТС.Прицепы || катагорияТС == КатегорияТС.Прицепы2 ||
                катагорияТС == КатегорияТС.Прицепы3)
                ПремияПоПолису = Тб * Кт * Кс;
            else if (катагорияТС == КатегорияТС.А)
                ПремияПоПолису = Тб * Кт * Кбм * Квс * Кс;
            else if (IsФизЛицо && катагорияТС == КатегорияТС.B)
                ПремияПоПолису = Тб * Кт * Кбм * Квс * Ко * Км * Кс;
            else if (IsФизЛицо)
                ПремияПоПолису = Тб * Кт * Кбм * Квс * Ко * Кс;

            else if (!IsФизЛицо && катагорияТС == КатегорияТС.B)
                ПремияПоПолису = Тб * Кт * Кбм * Ко * Км * Кс;
            else if (!IsФизЛицо)
                ПремияПоПолису = Тб * Кт * Кбм * Ко * Кс;

            var ПремияПоПолисуMax = Тб * Кт * 3;

            ПремияПоПолису = Math.Min(ПремияПоПолисуMax, ПремияПоПолису);
            return ПремияПоПолису;
        }

        public class ОСАГО_Км
        {
            public string Name { get; set; }
            public double Value { get; set; }

            public double PowerFrom { get; set; }
            public double PowerTo { get; set; }
        }

        public class ОСАГО_Квс
        {
            public string Name { get; set; }
            public double Value { get; set; }

            public int AgeFrom { get; set; }
            public int AgerTo { get; set; }

            public double СтажFrom { get; set; }
            public double СтажTo { get; set; }
        }

        public enum КатегорияТС
        {
            None,
            А,
            B,
            C,
            C2,
            D,
            D2,
            Тракторы,
            Прицепы,
            Прицепы2,
            Прицепы3
        }

        public string SaveSerializeOsago(string userId, string objectId, Osago obj, string objectName)
        {
            var serializer = new XmlSerializer(typeof(Osago));
            var sb = new StringBuilder();
            var w = new StringWriter(sb, CultureInfo.InvariantCulture);
            serializer.Serialize(w, obj);
            var values = new Dictionary<string, object>
                             {
                                 {"СсылкаНаОбъект", !string.IsNullOrEmpty(objectId) ? Convert.ToDecimal(objectId) : 0M},
                                 {"НазваниеОбъекта", "Расчёт, " + objectName},
                                 {"СохраненРасчет", false},
                                 {"УникальныйНомер", obj.UniqueNumber},
                                 {"ТипРасчета", "ОСАГО"},
                                 {"Xml", sb.ToString()}
                             };
            return rosModel.AddEntity(userId, "РасчётСтраховки", values).ToString();
        }

        #region IDisposable Members

        public void Dispose()
        {

        }

        #endregion

        public Dictionary<string, string> GetRegions()
        {
            return
                rosModel.GetEntities(
                    "[Типы=ЭлементСправочника;Колонки=(НазваниеОбъекта);Сортировки=(НазваниеОбъекта,Asc);Места=(Регионы,1)]",
                    new Dictionary<string, object>())
                    .ToDictionary(x => x["id_node"].ToString(), x => x["НазваниеОбъекта"].ToString());

        }


    }


}